#include "drivers/ext/disk_fatfs.h"
#include "fs_init_fatfs.h"
#include "sys_log.h"

#include <stdlib.h>

#define RAM_DISK_SECTION_SIZE (512)
#define RAM_DISK_SECTION_COUNT (256)
static uint8_t *ps_buf;

static DSTATUS _fatfs_disk_status(void);
static DSTATUS _fatfs_disk_initialize(void);
static DRESULT _fatfs_disk_read(BYTE *buff, LBA_t sector, UINT count);
static DRESULT _fatfs_disk_write(const BYTE *buff, LBA_t sector, UINT count);
static DRESULT _fatfs_disk_ioctl(BYTE cmd, void *buff);

static device_disk_fatfs_data_t s_data;

static struct device_disk_fatfs const s_device = {
    .api = {
        .disk_status = _fatfs_disk_status,
        .disk_initialize = _fatfs_disk_initialize,
        .disk_read = _fatfs_disk_read,
        .disk_write = _fatfs_disk_write,
        .disk_ioctl = _fatfs_disk_ioctl,
    },
    .data = &s_data,
};
OBJ_EXPORT_DEVICE(s_device, "disk:/ff:ram");

static DSTATUS _fatfs_disk_status(void)
{
    if (ps_buf)
        return RES_OK;
    else
        return RES_NOTRDY;
}

static DSTATUS _fatfs_disk_initialize(void)
{
    if (ps_buf == NULL)
    {
        ps_buf = malloc(RAM_DISK_SECTION_SIZE * RAM_DISK_SECTION_COUNT);
    }
    return _fatfs_disk_status();
}

static DRESULT _fatfs_disk_read(BYTE *buff, LBA_t sector, UINT count)
{
    if (ps_buf == NULL)
    {
        return RES_NOTRDY;
    }
    memcpy(buff, &ps_buf[RAM_DISK_SECTION_SIZE * sector], count * RAM_DISK_SECTION_SIZE);
    return RES_OK;
}

static DRESULT _fatfs_disk_write(const BYTE *buff, LBA_t sector, UINT count)
{
    memcpy(&ps_buf[RAM_DISK_SECTION_SIZE * sector], buff, count * RAM_DISK_SECTION_SIZE);
    return RES_OK;
}

static DRESULT _fatfs_disk_ioctl(BYTE cmd, void *buff)
{
    switch (cmd)
    {
    case CTRL_SYNC:
        break;
    case GET_SECTOR_COUNT:
        *(WORD *)buff = RAM_DISK_SECTION_COUNT;
        break;
    case GET_SECTOR_SIZE:
        *(WORD *)buff = RAM_DISK_SECTION_SIZE;
        break;
    case GET_BLOCK_SIZE:
        *(WORD *)buff = 1;
        break;
    case CTRL_TRIM:
        break;
    }
    return RES_OK;
}
